<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>方法返回值为子类对象1</title>
</head>
<body>
<script>
class MyArray{


  /*
  * 其实从这个案例里可以发现对象其实就是一个壳 其实操作的还是里面的数据
  * 比如Array对象操作它其实是在操作它内部的数据 使用方法操作内部的数据
  *
  *
  * */

  /*
  * 这里构造方法的逻辑是如果传值就用传的值 如果没传就用默认值 但是不能直接写
  * 要在构造函数内对传值的状态进行判断 不然不传值的话arr就是undefined 那么就会变成 this._arr = undefined
  *
  * 这里不像java可以写多个构造函数重载 可以调午餐的也可以调带参的
  * */
  constructor(arr =[],a = 0) {
    this._arr = arr
    this.a = a
  }

  push(ele){
    this._arr.push(ele)
  }

  /*
  * 这里的map是要返回一个新的对象(纯函数)为了确保返回的新对象依旧是子类对象的话这里创建返回对象的操作很特殊
  * 调用子类的构造函数创建一个新的对象
  * 这里有一点要注意因为这里调用子类的是无参构造函数所以可以直接使用 但是如果子类内部没有给属性赋予默认值，需要我们
  * 通过构造函数传值的话该怎么办呢？也就是说这里如果调用的是有参的构造函数 参数怎么传递过去呢？
  *对于这个问题首先要思考为什么要返回一个子类对象而不是一个随便创建的对象 因为为了沿用子类 即map函数的返回值也能够调用
  * 子类的方法，所以这里如果调用的是一个有参构造的话那我们可以将this上的对应属性传入
  *
  * 当然这里没有必要这样操作,因为返回的是一个数组直接 = []就行
  * 如果这里返回的是一个普通对象要这样操作 不能直接 = {}
  *
  *
  * */
  map(fn){
    let newArray = new this.constructor(undefined,this.a)
    console.log(newArray);
    for (let i = 0; i < this._arr.length; i++) {
      newArray.push(fn(this._arr[i],i))
    }
    return newArray
  }
}

class UserArray extends MyArray{
  constructor(arr,a) {
    super(arr,a);
  }

  print(){
    console.log('UserArray');
  }
}

let userArray = new UserArray([2,5,9,8,6],100);
console.log(userArray);
let res = userArray.map(ele =>ele+1)
console.log(res);
res.print()



</script>
</body>
</html>